#include "Comproctol.hpp"
#include<fstream>
#include<iostream>

#define DEBUG

SocketServer * server = SocketServer::getInstance();
shared_ptr<map<HSocket, ComProtocol::UserList> > UserList(new map<HSocket, ComProtocol::UserList >);
map <string, string> UserLogin;

template<typename T>
void pri(string Key, T Value, bool NewLine = true, int Tab = 0, int EndTab = 0)
{
	rep(i, 1, Tab * 4)
	{
		cout << " ";
	}
	cout << "[" << Key << "] " << Value;
	rep(i, 1, EndTab * 4)
	{
		cout << " ";
	}
	if (NewLine)cout << endl;
}

void Prepare() {
	ifstream ifs("User.txt");
	string t1, t2;
	while (ifs >> t1) {
		ifs >> t2;
		UserLogin[t1] = t2;
	}
}

void PrepareSta() {
	ifstream ifs("config.txt");
	HSocket PORT;
	ifs >> PORT;
	pri<unsigned short>("PORT", PORT);
	server->startServer(PORT, true, false);
}

void Login(HSocket it, shared_ptr<DataStream> dm) {
	ComProtocol::Send::Login login(dm);
	ComProtocol::Recv::Login *ret;
#ifdef DEBUG
	pri<HSocket>("UserLogin", it);
	pri<string>("ID", login.ID, true, 1);
	pri<string>("PWD", login.PWD, true, 1);
#endif // DEBUG

	if (UserLogin.find(login.ID)!=UserLogin.end() && UserLogin[login.ID]==login.PWD) {
		ComProtocol::UserList tmp(login.ID, it);
		UserList->insert(pair<HSocket, ComProtocol::UserList>(it,tmp));

#ifdef DEBUG
		pri<string>("New User", login.ID);
		pri<int>("Count", UserList->size());
#endif // DEBUG

		ret = new ComProtocol::Recv::Login(true);
	}
	else
	{
		ret = new ComProtocol::Recv::Login(false);
	}
	server->sendMessage(it, ret->Pack());
	delete ret;
}

void GlobalMsg(HSocket it, shared_ptr<DataStream> dm) {
	ComProtocol::Send::GlobalMsg sd(dm);
	ComProtocol::Recv::GlobalMsg ret(UserList->at(it).ID,sd.msg);

#ifdef DEBUG
	pri<string>("GlobalMSG", sd.msg);
#endif // DEBUG

	server->sendMessage(ret.Pack());
}

void GetList(HSocket it, shared_ptr<DataStream> dm) {
	ComProtocol::Send::GetList sd(dm);
	ComProtocol::Recv::GetList ret(UserList);
	server->sendMessage(it, ret.Pack());
}

void SendTo(HSocket it, shared_ptr<DataStream> dm) {
	ComProtocol::Send::SendTo sdata(dm);
	ComProtocol::Recv::SendTo ret(sdata.withstream, it);

#ifdef DEBUG
	pri<string>("SendTo", ":");
	pri<HSocket>("From", it, true, 1);
	pri<HSocket>("To", sdata.target_cli, true, 1);
	pri<int>("DataSize", sdata.withstream->Size(), true, 1);
	pri<int>("DataSize", ret.withstream->Size(), true, 1);
	//pri<bool>("Equal", Seek::CheckStringEqual(sdata.withstream->GetSrc(), ret.withstream->GetSrc(), false), true, 1);
#endif // DEBUG

	server->sendMessage(sdata.target_cli, ret.Pack());
}

int main() {

	server->onDisconnect = [](HSocket it) {
		pri<HSocket>("Disconnect", it);
		UserList->erase(it);
	};
	server->onError = [](ErrorCode ecode) {
		pri<int>("Error", ecode);
	};
	server->onNewConnection = [](HSocket it) {
		pri<HSocket>("NewConnect", it);
	};
	server->onRecv = [](HSocket it, shared_ptr<DataStream> dm) {
		ComProtocol::OperationType otype = ComProtocol::OperationType::Normal;
		dm->DoObj<ComProtocol::OperationType>(otype);
		switch (otype)
		{
		case ComProtocol::Normal:
			break;
		case ComProtocol::Login:
			Login(it, dm);
			break;
		case ComProtocol::GetList:
			GetList(it, dm);
			break;
		case ComProtocol::GetInfor:
			break;
		case ComProtocol::SendTo:
			SendTo(it, dm);
			break;
		case ComProtocol::GlobalMsg:
			GlobalMsg(it, dm);
			break;
		case ComProtocol::Quiet:
			break;
		default:
			break;
		}
	};

	server->onStart = [](const char * ip) {
		pri<string>("IP", ip);
	};

	Prepare();

	PrepareSta();

	getchar();

	return 0;
}
